﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using COFE.Core.Entry;
using COFE.Core;
using COFE.Core.Utils;
using System.Xml.Linq;
using COFE.Web;

namespace COFE.Web
{
    /// <summary>
    /// Abstract class that provide Metadata for interface that 
    /// inherited from IPropertyHost interface, 
    /// like IInternalFileSystemInfo, IEventLog and IEntryList.
    /// </summary>
    public abstract class PropertyHost<T> : SupportLink
    {
        #region Constructor

        /// <summary>
        /// Inherited class must set _entity or _metadataList or both.
        /// </summary>
        protected PropertyHost()
        {

        }

        protected PropertyHost(IPropertyHost<T> entry)
        {
            _entity = entry;
            MetadataProperties = EnumUtils<MetadataAttribute>.FilterPropertiesForAttribute(
                       _entity.GetSupportedProperty());
        }

        protected PropertyHost(MetadataList metadataList)
        {
            if (metadataList == null)
                throw new ArgumentNullException();
            _metadataList = metadataList;

            MetadataProperties = (from pp in metadataList
                                  where MetadataExtension.IsMetadata(pp.Property)
                                  select pp.Property).ToArray();
        }

        #endregion

        #region Methods

        public virtual PropertyPair GetProperty(object property)
        {
            try
            {
                if (_metadataList != null)
                    return _metadataList.Find(property);

                if (_entity != null)
                    return _entity.GetProperty(property);

                throw new Exception("Both metadata and entry is null.");
            }
            catch (Exception ex)
            { throw new ArgumentException("Get Property failed.", ex); }
        }


        public virtual PropertyPair GetProperty(string propertyName)
        {
            try
            {
                var property = COFEShared.PropertyDictionary.GetProperty(propertyName);
                if (property == null)
                    throw new ArgumentException("Property not registered.");

                if (_metadataList != null)
                    return GetProperty(property);

                if (_entity != null)
                    return _entity.GetProperty(property);

                throw new Exception("Both metadata and entry is null.");
            }
            catch (Exception ex)
            { throw new ArgumentException("Get Property failed.", ex); }
        }

        /// <summary>
        /// Write all Major Metadata to XElement.
        /// (Minor Metadata are output via Metadata.ToXml() method.)
        /// </summary>
        /// <param name="parentElement"></param>
        protected void writeMetadata(XElement parentElement, 
            bool writeMinor = false)
        {
            foreach (var meta in Metadata)
            {
                bool isMajorProp = MetadataExtension.getIsMajorProperty(meta.Property);
                

                if (isMajorProp)
                {
                    string property = COFEShared.PropertyDictionary
                        .GetPropertyString(meta.Property);
                    parentElement.Add(new XElement(
                        XName.Get(property, ServiceConstants.Namespace),
                        meta.Value.ToString()));
                }
                else
                    if (writeMinor)
                    {
                        string property = COFEShared.PropertyDictionary
                        .GetPropertyString(meta.Property);
                        parentElement.Add(new XAttribute(
                            XName.Get(property, ServiceConstants.Namespace),
                            meta.Value.ToString()));
                    }
            }
        }

      

        #endregion

        #region Data

        /// <summary>
        /// This may be always null.
        /// </summary>
        protected IPropertyHost<T> _entity = null;

        /// <summary>
        /// This is initalized in constructor or constructed when MetadataList called.
        /// </summary>
        protected MetadataList _metadataList = null;


        #endregion

        #region Public Properties

        public IPropertyHost<T> Entity { get { return _entity; } }

        public virtual object[] MetadataProperties { get; protected set; }

        /// <summary>
        /// Gets a list of metadata.
        /// </summary>
        public MetadataList Metadata
        {
            get
            {
                if (_metadataList == null)
                    _metadataList = new MetadataList(
                        from p in MetadataProperties
                        select GetProperty(p)
                        ); return _metadataList;
            }
            set { }
        }


        #endregion

    }
}
